LOAD DATA.

______________________________________________________________________________

• Neocortex_v3.RData Not necessary if just plotting on already calculated PCA, UMAP, clusters.

# Full dataset:
load("../data/cfc4b2_neocortex_v3.RData")

# 40k random subset (toy dataset)
# ncx.40k <- read_rds("constellation_plots/ncx_v3_40k.rds")

# 100k random subset of excitatory neuron lineage only.
ncx.exn.100k <- read_rds("../data/exn_lineage/toy/ncx.v3.exn.sub_100k.rds")

• Cluster / marker tables.

********************************************************************

1. START scrattch.hicat functions to build constellation plots.

********************************************************************

1. Define cells to build the plot from.

[All cells: 404.2K]

a. All clusters / cell types:

Keep only cells with combo2 $combined.cluster.2 annotation.

b. Excitatory neuron lineage only:

Keep only cells with combo2 $combined.cluster.2 annotation AND whose $combined.cluster.2 annotation belongs to excitatory neuronal lineage classes.

b.1. Cells in exn linage 100k cell toy object:

2. Build dataframes for constellation plots.

1. cl

2. rd.dat

3. cl.df

4. rd.cl.center Find cluster centers from UMAP coordinates

5. cl.center.df

Join cl.df and rd.cl.center into cl.center.df for input into get_KNN_graph.

6. knn.cl

3. Make constellation plot

——————————————————————————

2. Find DE genes between connected clusters.

——————————————————————————

Neuron_3 cells with nearest neighbors in Neuron_8

Compare cells above and below the median count of neuron_8 neighbors.

cells <- list()
cells$above.median <- x %>% filter(neuron_8 > median) %>% pull(cell.name)
cells$below.median <- x %>% filter(neuron_8 < median)  %>% pull(cell.name)

s.obj <- SetIdent(Neocortex, cells = cells$above.median, value = 'nn_above_med') %>% 
          SetIdent(cells = cells$below.median, value = 'nn_below_med')

markers <- list()
markers$nn_above_med <- FindMarkers(s.obj, slot = "scale.data", 
                                  # cells.1 = cells$above.median, cells.2 = cells$below.median,
                                  ident.1 = "nn_above_med", ident.2 = "nn_below_med", 
                                  logfc.threshold = 0)

Calculate enrichment ratio, filter genes w. adj p-value < 0.05, sort table. Positive values indicate that the feature is more highly expressed in the first group.


markers.tmp <- markers$nn_above_med %>% rownames_to_column("gene") %>%
  mutate(enrich.ratio = pct.1 / pct.2,
         gene.score = avg_diff * enrich.ratio,
         across(.cols = where(is.numeric), .fns = round, digits = 5)
  ) %>%
  filter(p_val_adj <= 0.05) %>% 
  select(gene, pct.1, pct.2, enrich.ratio, avg_diff, gene.score, p_val_adj) %>%
  arrange(desc(gene.score))

write_tsv(markers.tmp, "../out/DEgenes_neuron3_vs_neuron8.tsv")

Make heatmap:

Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()
LS0tCnRpdGxlOiAiQ29uc3RlbGxhdGlvbiBQbG90czogTmVvY29ydGV4LCAybmQgVHJpbWVzdGVyIiAKc3VidGl0bGU6ICJBbGwgU2FtcGxlcywgQWxsIGNlbGwgdHlwZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTgsIGZpZy5wYXRoPSdGaWdzLycsCiAgICAgICAgICAgICAgICAgICAgICBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpyZWFjdGFibGUgPC0gZnVuY3Rpb24oLi4uKSB7CiAgaHRtbHRvb2xzOjp0YWdMaXN0KHJlYWN0YWJsZTo6cmVhY3RhYmxlKC4uLikpCn0KCnNldHdkKCJ+L3Blcm1hbmVudGhlYWRkYW1hZ2VQSEQvY29uc3RlbGxhdGlvbl9wbG90cy9SLyIpCiMgYXR0YWNoKC5lbnYpCgojIHNvdXJjZSgiLi4vLi4vLi4vY29kZV9nZW5lcmFsL3NldHVwX1Jfc2Vzc2lvbl9DU0UuUiIpCnNvdXJjZV9ybWQoInNjcmF0dGNoLmhpY2F0X2Z4bnMuUm1kIikKCnNvdXJjZV9ybWQgPC0gZnVuY3Rpb24oZmlsZSwgbG9jYWwgPSBGQUxTRSwgLi4uKXsKICBvcHRpb25zKGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICdhbGxvdycpCgogIHRlbXBSIDwtIHRlbXBmaWxlKHRtcGRpciA9ICIuIiwgZmlsZWV4dCA9ICIuUiIpCiAgb24uZXhpdCh1bmxpbmsodGVtcFIpKQogIGtuaXRyOjpwdXJsKGZpbGUsIG91dHB1dD10ZW1wUiwgcXVpZXQgPSBUUlVFKQoKICBlbnZpciA8LSBnbG9iYWxlbnYoKQogIHNvdXJjZSh0ZW1wUiwgbG9jYWwgPSBlbnZpciwgLi4uKQp9CmBgYAoKIyBMT0FEIERBVEEuCiMgX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCgrigKIgTmVvY29ydGV4X3YzLlJEYXRhCk5vdCBuZWNlc3NhcnkgaWYganVzdCBwbG90dGluZyBvbiBhbHJlYWR5IGNhbGN1bGF0ZWQgUENBLCBVTUFQLCBjbHVzdGVycy4KYGBge3IgZXZhbCA9IEZBTFNFLCBlY2hvPVRSVUV9CiMgRnVsbCBkYXRhc2V0Ogpsb2FkKCIuLi9kYXRhL2NmYzRiMl9uZW9jb3J0ZXhfdjMuUkRhdGEiKQoKIyA0MGsgcmFuZG9tIHN1YnNldCAodG95IGRhdGFzZXQpCiMgbmN4LjQwayA8LSByZWFkX3JkcygiY29uc3RlbGxhdGlvbl9wbG90cy9uY3hfdjNfNDBrLnJkcyIpCgojIDEwMGsgcmFuZG9tIHN1YnNldCBvZiBleGNpdGF0b3J5IG5ldXJvbiBsaW5lYWdlIG9ubHkuCm5jeC5leG4uMTAwayA8LSByZWFkX3JkcygiLi4vZGF0YS9leG5fbGluZWFnZS90b3kvbmN4LnYzLmV4bi5zdWJfMTAway5yZHMiKQpgYGAKCuKAoiBDbHVzdGVyIC8gbWFya2VyIHRhYmxlcy4KYGBge3IgcGFnZWQucHJpbnQ9VFJVRX0KbmN4LmNsdXN0ZXJzIDwtIHJlYWRfZGVsaW0oIi4uL3RibHMvODNkMTlfTmVvY29ydGV4X2FsbGluZGl2aWR1YWxzX2NvbWJpbmVkY2x1c3RlcnNfdjEudHh0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkKCm5jeC5tYXJrZXJzIDwtIHJlYWRfZGVsaW0oIi4uL3RibHMvOGYwZmNfTmVvY29ydGV4X3N1YnNldDFfY2x1c3Rlcm1hcmtlcnNfY29tYm8yLnR4dCIsIAogICAgICAgICAgICAgICAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQpgYGAKCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKIyAxLiBTVEFSVCBgc2NyYXR0Y2guaGljYXRgIGZ1bmN0aW9ucyB0byBidWlsZCBjb25zdGVsbGF0aW9uIHBsb3RzLgojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCgojIyAxLiBEZWZpbmUgY2VsbHMgdG8gYnVpbGQgdGhlIHBsb3QgZnJvbS4KW0FsbCBjZWxsczogNDA0LjJLXQogIAojIyMgYS4gQWxsIGNsdXN0ZXJzIC8gY2VsbCB0eXBlczoKCktlZXAgb25seSBjZWxscyB3aXRoICpfY29tYm8yXyogYCRjb21iaW5lZC5jbHVzdGVyLjJgIGFubm90YXRpb24uCmBgYHtyIGV2YWw9RkFMU0V9CgpjZWxscy5jbC5kZiA8LSAgbmN4LmNsdXN0ZXJzICU+JSBmaWx0ZXIoc3RyX2RldGVjdChjb21iaW5lZC5jbHVzdGVyLjIsICJjb21ibzIiKSkKCnMub2JqIDwtIE5lb2NvcnRleCAlPiUgc3Vic2V0U2V1cmF0KGNlbGxzLmtlZXAgPSBjZWxscy5jbC5kZiRjZWxsLm5hbWUpCiMgMzQ4SyBjZWxscwoKIyBTYW5pdHkgY2hlY2sKY2VsbHMuY2wuZGYkY2VsbC5uYW1lICU+JSBpZGVudGljYWwocy5vYmpAbWV0YS5kYXRhICU+JSByb3duYW1lcykKW1RSVUVdCmBgYAoKIyMjIGIuIEV4Y2l0YXRvcnkgbmV1cm9uIGxpbmVhZ2Ugb25seToKCktlZXAgb25seSBjZWxscyB3aXRoICpfY29tYm8yXyogYCRjb21iaW5lZC5jbHVzdGVyLjJgIGFubm90YXRpb24gQU5ECndob3NlIGAkY29tYmluZWQuY2x1c3Rlci4yYCBhbm5vdGF0aW9uIGJlbG9uZ3MgdG8gZXhjaXRhdG9yeSBuZXVyb25hbCBsaW5lYWdlIGNsYXNzZXMuCmBgYHtyIGV2YWw9RkFMU0V9CmNlbGxzLmNsLmRmIDwtIG5jeC5jbHVzdGVycy5leG4gPC0gCiAgICAgICAgICAgICAgICAgIG5jeC5jbHVzdGVycyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc3RyX2RldGVjdChjb21iaW5lZC5jbHVzdGVyLjIsICJjb21ibzIiKSApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHN0cl9kZXRlY3QoY29tYmluZWQuY2x1c3Rlci4yLCAiTmV1cm9ufENSfERpdmlkaW5nfFJHfElQQ3xPUEMiKSApCiMgMjcxLjRLIGNlbGxzIGluIGV4Y2l0YXRvcnkgbGluZWFnZS4KYGBgCgojIyMgYi4xLiBDZWxscyBpbiBleG4gbGluYWdlIDEwMGsgY2VsbCB0b3kgb2JqZWN0OgpgYGB7cn0KIyBEZWZpbmUgd2hpY2ggb2JqZWN0IHRoZSBjb25zdGVsbGF0aW9uIHBsb3QgaXMgYmFzZWQgb246CnMub2JqIDwtIG5jeC5leG4uMTAwawoKY2VsbHMuY2wuZGYgPC0gbmN4LmNsdXN0ZXJzICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKGNlbGwubmFtZSAlaW4lIHJvd25hbWVzKHMub2JqQG1ldGEuZGF0YSkgKQpgYGAKCiMjIDIuIEJ1aWxkIGRhdGFmcmFtZXMgZm9yIGNvbnN0ZWxsYXRpb24gcGxvdHMuCgojIyMgMS4gYGNsYCAKYGBge3J9CmNsIDwtIGNlbGxzLmNsLmRmJGNvbWJpbmVkLmNsdXN0ZXIuMiAlPiUgYXMuZmFjdG9yICU+JSAKICAgICAgICAgIHNldF9uYW1lcyhjZWxscy5jbC5kZiRjZWxsLm5hbWUpCiMgMTI4IGNsdXN0ZXJzIGluIGFsbCBfY29tYm8yXyBjZWxscwojIDc3IGNsdXN0ZXJzIGluIGFsbCBfY29tYm8yXyAmIEV4TiBsaW5lYWdlIGNlbGxzLgpgYGAKCiMjIyAyLiBgcmQuZGF0YApgYGB7cn0KcmQuZGF0IDwtIGxpc3QodW1hcCA9IHMub2JqQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3MsCiAgICAgICAgICAgICAgIHBjYSA9IHMub2JqQHJlZHVjdGlvbnMkcGNhQGNlbGwuZW1iZWRkaW5ncykKCiMgU3Vic2V0IFVNQVAgYW5kIFBDQSBjZWxsIGVtYmVkZGluZ3M6IGtlZXAgb25seSBjZWxscyBpbiBuY3guY2x1c3RlcnMuCiMgKEV4Y2x1ZGUgY2VsbHMgaW4gY2x1c3RlciAwIGFuZCBrZWVwIG9ubHkgY2VsbHMgd2l0aCAiY29tYm8yIiBpbiBjb21iaW5lZCBjbHVzdGVyIDIgbmFtZS4pCiMgcmQuZGF0ICU8PiUgbGFwcGx5KGZ1bmN0aW9uKHgpIHhbbmFtZXMoY2wpLCBdKQpgYGAKCiMjIyAzLiBgY2wuZGZgCmBgYHtyfQpjbC5kZiA8LSBnZXRfY2xfZGYoY2wpCgpjbC5kZiRjbGFkZSA8LSBzdHJfc3BsaXRfZml4ZWQoY2wuZGYkY2x1c3Rlcl9sYWJlbCwgIl8iLCAyKVsgLDFdICU+JSB0b2xvd2VyIAojIEFkZCBjbGFkZV9pZCwgY2xhZGVfY29sb3IgdG8gY2wuZGYKY2xhZGUuY29scyA8LSBkYXRhLmZyYW1lKCMgY2xhZGUgPSB1bmlxdWUoY2wuZGYkY2xhZGUpLAogICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbG9yID0gYygiY3IiPSAiZGFya2dyZXkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkaXZpZGluZyIgPSAiZGFya2toYWtpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibmV1cm9uIiA9ICJkZWVwc2t5Ymx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImludGVuZXVyb24iID0gImRlZXBwaW5rMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlwYyIgPSAiYnJvd240IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWljcm9nbGlhIiA9ICJkYXJrb3JjaGlkMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3BjIiA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdGhlciIgPSAiZGFya3NsYXRlYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJnIiA9ICJkYXJrb3JhbmdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidmFzY3VsYXIiID0gImJsYW5jaGVkYWxtb25kIikKICAgICAgICAgICAgKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJjbGFkZSIpCgpjbC5kZiAlPD4lIGxlZnRfam9pbihjbGFkZS5jb2xzKQpybShjbGFkZS5jb2xzKQoKIyBjZWxscy5jbC5kZjogQWRkIGNsdXN0ZXJfaWQgY29sdW1uIGZyb20gY2wuZGY7IHJlbW92ZSB1bnVzZWQgY29sdW1ucy4gCmNlbGxzLmNsLmRmIDwtIGxlZnRfam9pbihjZWxscy5jbC5kZiAlPiUgc2VsZWN0KGNlbGwubmFtZSwgY2VsbC50eXBlLCBjb21iaW5lZC5jbHVzdGVyLjIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbC5kZiAlPiUgc2VsZWN0KGNsdXN0ZXJfbGFiZWwsIGNsdXN0ZXJfaWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJjb21iaW5lZC5jbHVzdGVyLjIiID0gImNsdXN0ZXJfbGFiZWwiKQogICAgICAgICAgICAgICAgKSAlPiUgbXV0YXRlKGNsdXN0ZXJfaWQgPSBhcy5mYWN0b3IoY2x1c3Rlcl9pZCkpCmBgYAoKIyMjIDQuIGByZC5jbC5jZW50ZXJgIEZpbmQgY2x1c3RlciBjZW50ZXJzIGZyb20gVU1BUCBjb29yZGluYXRlcwpgYGB7cn0KcmQuY2wuY2VudGVyIDwtIGdldF9SRF9jbF9jZW50ZXIocmQuZGF0JHVtYXAsIGNsKSAKCnJkLmNsLmNlbnRlciAlPD4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIHNldF9uYW1lcyhjKCJ4IiwgInkiKSkgJT4lCiAgYWRkX2NvbHVtbihjbCA9IDE6bnJvdyhyZC5jbC5jZW50ZXIpLCAuYmVmb3JlID0gIngiKSAlPiUKICAjIGFkZF9jb2x1bW4gcHJlc2VydmVzIHJvd25hbWVzLgogICMgYnV0IG1vdmluZyByb3duYW1lcyB0byBjb2x1bW4gY2x1c3Rlcl9sYWJlbCBhbnl3YXkgYmMgb2YgbGVmdF9qb2luIGJlbG93LgogIHJvd25hbWVzX3RvX2NvbHVtbigiY2x1c3Rlcl9sYWJlbCIpCmBgYAoKIyMjIyA1LiBgY2wuY2VudGVyLmRmYApKb2luIGBjbC5kZmAgYW5kIGByZC5jbC5jZW50ZXJgIGludG8gYGNsLmNlbnRlci5kZmAgZm9yIGlucHV0IGludG8gYGdldF9LTk5fZ3JhcGhgLgpgYGB7cn0KY2wuY2VudGVyLmRmIDwtIGxlZnRfam9pbihyZC5jbC5jZW50ZXIsIGNsLmRmLAogICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoImNsdXN0ZXJfbGFiZWwiKSkgCmBgYAoKIyMjIyA2LiBga25uLmNsYCAKYGBge3J9CiMgRml4ZXMgbmVlZGVkIGZvciBwcm9wZXIgb3V0cHV0IG9mIGtubi5jbC5kZgojIGNsLmNlbnRlci5kZiAlPD4lIHJlbmFtZShjbHVzdGVyX3NpemUgPSAic2l6ZSIpCiMgbGV2ZWxzKGNsKSA8LSBjbC5kZiRjbHVzdGVyX2lkCmNsLm51bWVyaWMgPC0gY2wKbGV2ZWxzKGNsLm51bWVyaWMpIDwtIGNsLmRmJGNsdXN0ZXJfaWQKCmtubi5yZXN1bHQgPC0gUkFOTjo6bm4yKGRhdGEgPSByZC5kYXQkcGNhWywgMToxMF0sIGsgPSAxNSkKCmtubi5jbCA8LSBnZXRfa25uX2dyYXBoKHJkLmRhdCA9IHJkLmRhdCRwY2FbICwgMToxMF0sIAogICAgICAgICAgICAgICAgICAgICAgICBjbC5kZiA9ICBjbC5kZiwgY2wgPSBjbC5udW1lcmljLCAKICAgICAgICAgICAgICAgICAgICAgICAgayA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAga25uLm91dGxpZXIudGggPSAyLCBvdXRsaWVyLmZyYWMudCA9IDAuNSkKCnJtKHJkLmRhdCwgbmN4LmNsdXN0ZXJzKQpgYGAKCiMjIDMuIE1ha2UgY29uc3RlbGxhdGlvbiBwbG90CmBgYHtyIGV2YWw9RkFMU0V9CiMgS2VlcCBvbmx5IGNlbGxzIHdoZXJlICRmcmFjIFtmcmFjdGlvbiBvZiBjZWxscyBpbiBjbHVzdGVyIHdpdGggbmVhcmVzdCBuZWlnaGJvcnMgaW4gZGlmZmVyZW50IGNsdXN0ZXJdID49IDAuMDUuCiMgRGVmaW5lZCBpbiBgZ2V0X2tubl9ncmFwaGA6IAojIGtubi5jbC5kZiRmcmFjID0ga25uLmNsLmRmJEZyZXEgLyBrbm4uY2wuZGYkY2wuZnJvbS50b3RhbAojIDEwJSA6IDIxMyBlZGdlcwprbm4uY2wuZGYgPC0ga25uLmNsJGtubi5jbC5kZiAgJT4lIGZpbHRlcihmcmFjID49IDAuMSkKCiMgUGxvdCBvbmx5IGVkZ2VzIGJldHdlZW4gRXhOIGxpbmVhZ2UgY2x1c3RlcnMuCiMga25uLmNsLmRmICU8PiUgZmlsdGVyX2F0KHZhcnMoY2wuZnJvbS5sYWJlbCwgY2wudG8ubGFiZWwpLCAKIyAgICAgICAgICAgICAgICAgICAgICAgIGFsbF92YXJzKHN0cl9kZXRlY3QoLiwgIlJHfElQQ3xOZXVyb258T1BDfERpdmlkaW5nIikpCiMgICAgICAgICAgICAgICkKCmNsLmNlbnRlci5kZiRjbHVzdGVyX2xhYmVsICU8PiUgc3RyX3JlbW92ZSgiX2NvbWJvMiIpCiAgCmNsLnBsb3QgPC0gcGxvdF9jb25zdGVsbGF0aW9uKGtubi5jbC5kZiwgY2wuY2VudGVyLmRmLCBvdXQuZGlyID0gIi4uL291dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUubGFiZWwgPSAiY2x1c3Rlcl9sYWJlbCIsIGV4eGFnZXJhdGlvbiA9IDEsIGN1cnZlZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnBhcnRzID0gRkFMU0UsIHBsb3QuaHVsbCA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LmhlaWdodCA9IDQwLCBwbG90LndpZHRoID0gNDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUuZG9kZ2UgPSBUUlVFLCBsYWJlbC5zaXplID0gMiwgbWF4X3NpemUgPSAyMCkKCmBgYAoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyAyLiBGaW5kIERFIGdlbmVzIGJldHdlZW4gY29ubmVjdGVkIGNsdXN0ZXJzLgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpgYGB7cn0KIyBEYXRhZnJhbWUgdy8gdGhlIHByb3BvcnRpb24gb2YgaygxNSkgbmVhcmVzdCBuZWlnaGJvcnMgaW4gZWFjaCBjbHVzdGVyIGZvciBldmVyeSBjZWxsLgpubi5jbC5kZiA8LSBrbm4uY2wkcHJlZC5yZXN1bHQkcHJlZC5wcm9iICU+JSBhcy5kYXRhLmZyYW1lCgpjbC5kZiRjbHVzdGVyX2lkICU8PiUgYXMuZmFjdG9yKCkKIyBQb3NzaWJseSBtb3ZlIHRvIHRvcCwgYmVmb3JlIG1ha2luZyBhbGwgREZzLgpjZWxscy5jbC5kZiAlPD4lIHJlbmFtZShjbHVzdGVyX2xhYmVsID0gImNvbWJpbmVkLmNsdXN0ZXIuMiIpICU+JSAKICAgICAgICAgICAgICAgICAgbXV0YXRlKGNsdXN0ZXJfbGFiZWwgPSBzdHJfcmVtb3ZlKGNsdXN0ZXJfbGFiZWwsICJfY29tYm8yIikpCgpjbC5kZiAlPD4lIG11dGF0ZShjbHVzdGVyX2xhYmVsID0gc3RyX3JlbW92ZShjbHVzdGVyX2xhYmVsLCAiX2NvbWJvMiIpKQoKCiMgQWRkIGNvbHVtbiB3aXRoIGNlbGxzJyBvd24gY2x1c3RlciBhc3NpZ25tZW50IGZyb20gYGNlbGxzLmNsLmRmYC4Kbm4uY2wuZGYgJTw+JSBsZWZ0X2pvaW4oY2VsbHMuY2wuZGYsCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygicXVlcnkiID0gImNlbGwubmFtZSIpCiAgICAgICAgICAgICAgICAgICAgICAgICkKIyBBZGQgY2x1c3Rlcl9sYWJlbCBjb3JyZXNwb25kaW5nIHRvIG5uLmNsLgoKbm4uY2wuZGYgJTw+JSBsZWZ0X2pvaW4oY2wuZGYgJT4lIHNlbGVjdChjbHVzdGVyX2xhYmVsLCBjbHVzdGVyX2lkKSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJubi5jbCIgPSAiY2x1c3Rlcl9pZCIpKQoKbm4uY2wuZGYgJTw+JSBzZWxlY3QocXVlcnksIGNsdXN0ZXJfaWRfc2VsZiA9ICJjbHVzdGVyX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9sYWJlbF9zZWxmID0gImNsdXN0ZXJfbGFiZWwueCIsCiAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9pZF9ubiA9ICJubi5jbCIsCiAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9sYWJlbF9ubiA9ICJjbHVzdGVyX2xhYmVsLnkiLAogICAgICAgICAgICAgICAgICAgIGZyZXEgPSAiRnJlcSIpCgojIG5uLmNsLmRmICU8PiUgc2VsZWN0KHF1ZXJ5LCBjb21iaW5lZC5jbHVzdGVyLjIsIGNsdXN0ZXJfaWQsIG5uLmNsLCApCgpgYGAKCmBgYHtyfQp4IDwtIGZpbHRlcihrbm4uY2wka25uLmNsLmRmLCBmcmFjID49IDAuMSAmIGNsLmZyb20gIT0gY2wudG8pICU+JSBhcnJhbmdlKGNsLmZyb20pCmBgYAoKYGBge3J9Cmtubi5jbCRrbm4uY2wuY2wuY291bnRzICU+JSBoZWFkCmBgYAoKYGBge3J9CmNsLmRmCgp4IDwtIGZpbHRlcihubi5jbC5kZiwgY2x1c3Rlcl9sYWJlbF9zZWxmID09ICJOZXVyb25fOCIgJiBjbHVzdGVyX2xhYmVsX25uID09ICJOZXVyb25fMyIpCiMgMTIsMjAxIGNlbGxzIGluIE5ldXJvbl84Cgp4ICU+JSBmaWx0ZXIoZnJlcSA+IDApICU+JSAKICBnZ3Bsb3QoKSArIGdlb21fZGVuc2l0eShhZXMoZnJlcSkpCmBgYAoKTmV1cm9uXzMgY2VsbHMgd2l0aCBuZWFyZXN0IG5laWdoYm9ycyBpbiBOZXVyb25fOApgYGB7ciBlY2hvPVRSVUV9CnggPC0gY2VsbC5jbC5jb3VudHMgJT4lIGZpbHRlcihjbHVzdGVyX2xhYmVsID09ICJOZXVyb25fMyIpICU+JSByZW5hbWUobmV1cm9uXzggPSAiNDQiKQoKbWVkaWFuLm5uQ291bnRzIDwtIG1lZGlhbih4JG5ldXJvbl84W3gkbmV1cm9uXzggPiAwXSwgbmEucm0gPSBUUlVFKQpgYGAKCmBgYHtyfQogIGdncGxvdCh4KSArIAogICAgZ2d0aXRsZSgibmV1cm9uXzMgY2VsbHMgXG4gbi8xNSBuZWFyZXN0IG5laWdoYm9ycyBpbiBuZXVyb25fOCIpICsKICAgIAogICAgZ2VvbV9iYXIoYWVzKHggPSBuZXVyb25fOCkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbi5ubkNvdW50cywgY29sb3VyID0gInJlZCIpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IG1lZGlhbi5ubkNvdW50cyArIDEsIHkgPSA3MCwKICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJtZWRpYW4gPSAiLCBtZWRpYW4ubm5Db3VudHMpCiAgKSArIAogICAgeGxhYigiIyBvZiBuZXVyb25fOCBuZWlnaGJvcnMiKSArCiAgICB5bGFiKCIiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgCmBgYAoKQ29tcGFyZSBjZWxscyBhYm92ZSBhbmQgYmVsb3cgdGhlIG1lZGlhbiBjb3VudCBvZiBuZXVyb25fOCBuZWlnaGJvcnMuCmBgYHtyIGVjaG89VFJVRX0KY2VsbHMgPC0gbGlzdCgpCmNlbGxzJGFib3ZlLm1lZGlhbiA8LSB4ICU+JSBmaWx0ZXIobmV1cm9uXzggPiBtZWRpYW4pICU+JSBwdWxsKGNlbGwubmFtZSkKY2VsbHMkYmVsb3cubWVkaWFuIDwtIHggJT4lIGZpbHRlcihuZXVyb25fOCA8IG1lZGlhbikgICU+JSBwdWxsKGNlbGwubmFtZSkKCnMub2JqIDwtIFNldElkZW50KE5lb2NvcnRleCwgY2VsbHMgPSBjZWxscyRhYm92ZS5tZWRpYW4sIHZhbHVlID0gJ25uX2Fib3ZlX21lZCcpICU+JSAKICAgICAgICAgIFNldElkZW50KGNlbGxzID0gY2VsbHMkYmVsb3cubWVkaWFuLCB2YWx1ZSA9ICdubl9iZWxvd19tZWQnKQoKbWFya2VycyA8LSBsaXN0KCkKbWFya2VycyRubl9hYm92ZV9tZWQgPC0gRmluZE1hcmtlcnMocy5vYmosIHNsb3QgPSAic2NhbGUuZGF0YSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjZWxscy4xID0gY2VsbHMkYWJvdmUubWVkaWFuLCBjZWxscy4yID0gY2VsbHMkYmVsb3cubWVkaWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMSA9ICJubl9hYm92ZV9tZWQiLCBpZGVudC4yID0gIm5uX2JlbG93X21lZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMCkKYGBgCgpDYWxjdWxhdGUgZW5yaWNobWVudCByYXRpbywgZmlsdGVyIGdlbmVzIHcuIGFkaiBwLXZhbHVlIDwgMC4wNSwgc29ydCB0YWJsZS4KUG9zaXRpdmUgdmFsdWVzIGluZGljYXRlIHRoYXQgdGhlIGZlYXR1cmUgaXMgbW9yZSBoaWdobHkgZXhwcmVzc2VkIGluIHRoZSBmaXJzdCBncm91cC4KYGBge3IgZmlsdGVyLW1hcmtlcnMsIGVjaG89VFJVRX0KCm1hcmtlcnMudG1wIDwtIG1hcmtlcnMkbm5fYWJvdmVfbWVkICU+JSByb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAlPiUKICBtdXRhdGUoZW5yaWNoLnJhdGlvID0gcGN0LjEgLyBwY3QuMiwKICAgICAgICAgZ2VuZS5zY29yZSA9IGF2Z19kaWZmICogZW5yaWNoLnJhdGlvLAogICAgICAgICBhY3Jvc3MoLmNvbHMgPSB3aGVyZShpcy5udW1lcmljKSwgLmZucyA9IHJvdW5kLCBkaWdpdHMgPSA1KQogICkgJT4lCiAgZmlsdGVyKHBfdmFsX2FkaiA8PSAwLjA1KSAlPiUgCiAgc2VsZWN0KGdlbmUsIHBjdC4xLCBwY3QuMiwgZW5yaWNoLnJhdGlvLCBhdmdfZGlmZiwgZ2VuZS5zY29yZSwgcF92YWxfYWRqKSAlPiUKICBhcnJhbmdlKGRlc2MoZ2VuZS5zY29yZSkpCgp3cml0ZV90c3YobWFya2Vycy50bXAsICIuLi9vdXQvREVnZW5lc19uZXVyb24zX3ZzX25ldXJvbjgudHN2IikKYGBgCgpgYGB7ciByZW5kZXItdGFibGV9CnJlYWN0YWJsZShtYXJrZXJzLnRtcCwgZGVmYXVsdFBhZ2VTaXplID0gMTAwLAogICAgICAgICAgc2hvd1NvcnRhYmxlID0gVFJVRSwgcmVzaXphYmxlID0gVFJVRSwgaGlnaGxpZ2h0ID0gVFJVRSwgZmlsdGVyYWJsZSA9IFRSVUUsIG1pblJvd3MgPSAxMCwKICAgICAgICAgIHN0eWxlID0gbGlzdChmb250RmFtaWx5ID0gIldvcmsgU2Fucywgc2Fucy1zZXJpZiIsIGZvbnRTaXplID0gIjEycHgiKQogICkKYGBgCgpgYGB7cn0KIyBzYXZlV2lkZ2V0KG1hcmtlcnMudG1wLCBmaWxlID0gKQoKIyBTYW1lIGdlbmVzIGluIGJvdGggY29tcGFyaXNvbnMgKHNhbml0eSBjaGVjaykKeHRhYl9zZXQgPC0gZnVuY3Rpb24oQSxCKXsKICAgICAgICAgICAgICBib3RoICAgIDwtICB1bmlvbihBLEIpCiAgICAgICAgICAgICAgaW5BICAgICA8LSAgYm90aCAlaW4lIEEKICAgICAgICAgICAgICBpbkIgICAgIDwtICBib3RoICVpbiUgQgogICAgICAgICAgICAgIHJldHVybih0YWJsZShpbkEsaW5CKSkKICAgICAgICAgICAgfQp4dGFiX3NldChtYXJrZXJzJG5uX2Fib3ZlX21lZCRnZW1lLCBtYXJrZXJzJG5uX2JlbG93X21lZCRnZW5lKQpgYGAKCk1ha2UgaGVhdG1hcDoKYGBge3IgaGVhdG1hcH0KdG1wLnNvYmogPC0gc3Vic2V0U2V1cmF0KHMub2JqLCBjZWxscy5rZWVwID0gZmxhdHRlbl9jaHIoY2VsbHMpKQoKbWluKHRtcC5zb2JqQGFzc2F5cyRSTkFAc2NhbGUuZGF0YSkKCmhlYXRtYXAgPC0gCiAgRG9IZWF0bWFwKHRtcC5zb2JqLCAKICAgICAgICAgICMgY2VsbHMgPSBmbGF0dGVuX2NocihjZWxscyksCiAgICAgICAgICBmZWF0dXJlcyA9IG1hcmtlcnMudG1wICU+JSAKICAgICAgICAgICAgIyBmaWx0ZXIocGN0LjEgPiAwLjI1KSAlPiUgZmlsdGVyKHBjdC4yIDwgMC4yKSAlPiUgCiAgICAgICAgICAgIHB1bGwoZ2VuZSksCiAgICAgICAgICBkaXNwLm1pbiA9IC0yLAogICAgICAgICAgZGlzcC5tYXggPSA3LAogICAgICAgICAgYW5nbGUgPSAwCiAgICAgICAgICAjIHNsb3QgPSAiZGF0YSIKICAgICAgICAgICMgc2xpbS5jb2wubGFiZWwgPSBUUlVFLAogICAgICAgICAgIyByZW1vdmUua2V5ID0gVFJVRQopICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpLAogICAgICAgICAgCiAgICAgICAgIyBhc3BlY3QucmF0aW8gPSBjKDEsMikKICApICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhlbmQgPSAxLCBuYS52YWx1ZSA9ICd3aGl0ZScsIG9wdGlvbiA9ICJtYWdtYSIsIGRpc2NyZXRlID0gRkFMU0UpCgojIGdnc2F2ZShmaWxlbmFtZSA9ICIuLi9ERWdlbmVzX25ldXJvbjNfdnNfbmV1cm9uOF9oZWF0bWFwLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSAiaW4iICkKCmdncGxvdGx5KGhlYXRtYXAsIHRvb2x0aXAgPSAiRmVhdHVyZSIpICU+JSBsYXlvdXQoYXV0b3NpemUgPSBGLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDUwMCkKCmBgYAoKCg==